package org.platform.processor.diagnose;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.platform.constant.DiagnoseConst;
import org.platform.core.JobManager;
import org.platform.dao.mapper.*;
import org.platform.mo.bussmo.diagnose.test.*;
import org.platform.mo.csmo.common.LoopTests;
import org.platform.mo.csmo.common.TestChannelBean;
import org.platform.mo.db.*;
import org.platform.processor.diagnose.job.PromoteTestDiagnoseResultJob;
import org.platform.tool.helper.LogHelper;
import org.platform.tool.util.BeansUtils;
import org.platform.tool.util.ComUtils;
import org.platform.tool.util.JsonUtils;
import org.platform.tool.util.XmlUtils;
import org.quartz.JobKey;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.JobDetailImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 处理诊断结果
 *
 * @author FengJie
 * @date 2018/7/21
 */
@Service
@Slf4j
public class DiagnoseResultProcessor {
    @Autowired
    private FdDiagnosetaskMapper diagnoseTaskMapper;
    @Autowired
    private FdDiagnosetaskTestMapper testMapper;
    @Autowired
    private FdDiagnoseTaskResultTestMapper resultTestMapper;
    @Autowired
    private FdTestchannelMapper channelMapper;
    @Autowired
    private FdTestresultsGtMapper gtResultMapper;
    @Autowired
    private FdTestresultsLinkMapper linkResultMapper;
    @Autowired
    private FdTestparamsLinkMapper linkParamsMapper;
    @Autowired
    private FdTestResultsBerMapper berResultMapper;
    @Autowired
    private FdTestparamsBerMapper berParamsMapper;
    @Autowired
    private DiagnoseRecordProcessor recordProcessor;
    @Autowired
    private JobManager jobManager;
    @Autowired
    private LogHelper logHelper;

    /**
     * 解析 [测试取消响应] 的内容
     *
     * @param xml xml文本
     */
    public void resolveTestCancelAck(String xml) {
        TestCancelAck testCancelAck = XmlUtils.xmlToBean(xml, TestCancelAck.class, true, "InterFaceFile");
        TestCancelAckContent content = testCancelAck.getContent();
        modifyTestResultByDiagnoseId(content.getTestPlanID(), DiagnoseConst.DIAGNOSE_STATUS_FAILURE);
        logHelper.normal("接收到取消测试响应文件,取消" + getChineseResult(content.getResult()) + content.getErrorReason(), content.getTestPlanID(), null);
    }

    /**
     * 解析 [测试计划响应] 内容
     *
     * @param xml xml
     */
    public void resolveTestPlanAck(String xml) {
        TestPlanAck testPlanAck = XmlUtils.xmlToBean(xml, TestPlanAck.class, true, "InterFaceFile");
        TestPlanAckContent content = testPlanAck.getContent();
        modifyTestResultByDiagnoseId(content.getTestPlanID(), DiagnoseConst.DIAGNOSE_STATUS_FAILURE);
        logHelper.normal("接收到测试响应文件,创建" + getChineseResult(content.getResult()), content.getTestPlanID(), null);
    }

    /**
     * 解析[测试结果]
     *
     * @param xml xml
     */
    @Transactional(rollbackFor = Exception.class)
    public void resolveTestResult(String xml) {
        TestResult testResult = XmlUtils.xmlToBean(xml, TestResult.class, true, "InterFaceFile");
        TestResultContent content = testResult.getContent();
        String diagnoseId = content.getTestPlanID();
        Integer executorStatus = getExecutorStatus(content.getResult());
        modifyTestResultByDiagnoseId(diagnoseId, executorStatus);

        Integer result = getIntegerResult(content.getResult());
        String stationID = content.getStationID();

        if (null != content.getGtList()) {
            saveGtResult(content.getGtList(), diagnoseId, result, stationID);
        }
        if (null != content.getBerList()) {
            saveBerResult(content.getBerList(), diagnoseId, result, stationID);
        }
        if (null != content.getLinkList()) {
            saveLinkResult(content.getLinkList(), diagnoseId, result, stationID);
        }
        recordProcessor.saveDiagnoseRecord(content.getTestPlanID(), "测试诊断结束,最终结果:" + getChineseResult(content.getResult()));
        promoteJob(content);
        logHelper.normal("结论:测试诊断结束,最终结果:" + getChineseResult(content.getResult()), diagnoseId, null);
    }

    /**
     * 解析 [任务模块主动取消测试任务]
     *
     * @param xml 取消xml
     */
    @Transactional(rollbackFor = Exception.class)
    public void resolveTestCancelMsg(String xml) {
        TaskTestCancelMsg testCancel = XmlUtils.xmlToBean(xml, TaskTestCancelMsg.class, true, "InterFaceFile");
        TaskTestCancelMsgContent content = testCancel.getContent();
        FdDiagnosetask diagnoseTask = new FdDiagnosetask();
        diagnoseTask.setDiagnoseid(content.getTestPlanID());
        diagnoseTask.setStatus(DiagnoseConst.DIAGNOSE_STATUS_ABORT);
        diagnoseTask.setEndtime(System.currentTimeMillis());
        diagnoseTaskMapper.updateByPrimaryKeySelective(diagnoseTask);

        FdDiagnosetaskTest testDiagnose = new FdDiagnosetaskTest();
        testDiagnose.setId(content.getTestPlanID());
        testDiagnose.setStatus(DiagnoseConst.DIAGNOSE_STATUS_ABORT);
        testDiagnose.setEndtime(System.currentTimeMillis());
        testMapper.updateByPrimaryKeySelective(testDiagnose);
        logHelper.normal("取消任务测试诊断任务【成功】,取消原因" + content.getCancelReason(), content.getTestPlanID(), null);
    }

    /**
     * 查询测试结果
     *
     * @param diagnoseId 诊断ID
     * @return
     */
    public TestResultContent queryTestDiagnoseResult(String diagnoseId) {
        Example example = new Example(FdTestchannel.class);
        example.createCriteria().andEqualTo("diagnoseid", diagnoseId);

        FdDiagnoseTaskResultTest diagnoseResult = resultTestMapper.selectByPrimaryKey(diagnoseId);
        TestResultContent result = new TestResultContent();

        if (diagnoseResult != null) {
            result.setTestPlanID(diagnoseId);
            result.setResult(diagnoseResult.getResult());
            result.setStationID(diagnoseResult.getStationid());
            result.setErrorReason(diagnoseResult.getErrorReason());

            //查询多个通道
            List<FdTestchannel> channelList = channelMapper.selectByExample(example);
            for (FdTestchannel channel : channelList) {
                Example channelExample = new Example(FdTestchannel.class);
                channelExample.createCriteria()
                        .andEqualTo("diagnoseid", diagnoseId)
                        .andEqualTo("channelid", channel.getChannelid());
                switch (channel.getTesttype()) {
                    case DiagnoseConst.GT_DIAGNOSE_TEST:
                        List<FdTestresultsGt> gtList = gtResultMapper.selectByExample(channelExample);
                        if (result.getGtList() == null) {
                            result.setGtList(new ArrayList<>());
                        }
                        result.getGtList().add(gtGt(gtList));
                        break;
                    case DiagnoseConst.LINK_DIAGNOSE_TEST:
                        List<FdTestresultsLink> linkList = linkResultMapper.selectByExample(channelExample);
                        if (result.getLinkList() == null) {
                            result.setLinkList(new ArrayList<>());
                        }
                        result.getLinkList().addAll(getLinkList(linkList));
                        break;
                    case DiagnoseConst.BER_DIAGNOSE_TEST:
                        List<FdTestResultsBer> breList = berResultMapper.selectByExample(channelExample);
                        if (result.getBerList() == null) {
                            result.setBerList(new ArrayList<>());
                        }
                        result.getBerList().add(getBer(breList));
                        break;
                    case DiagnoseConst.ANT_DIAGNOSE_TEST:
                        break;
                    default:
                }
            }
        }
        return result;
    }


    /**
     * gt值转化
     * 数据库结构->文档结构
     *
     * @param gtResultList 数据库结构
     * @return 文档结构
     */
    private TestResultGT gtGt(List<FdTestresultsGt> gtResultList) {
        TestResultGT testResultGT = new TestResultGT();
        //基于每个通道的  频点值  分组
        Map<Integer, List<FdTestresultsGt>> frequencyMap = gtResultList.stream().collect(Collectors.groupingBy(FdTestresultsGt::getFrequency));
        frequencyMap.forEach((frequency, fdGtList) -> {
            List<SignalGTResult> signalGTResultList = new ArrayList<>(fdGtList.size());
            fdGtList.forEach(gt -> {
                SignalGTResult signalGTResult = new SignalGTResult();
                BeanUtils.copyProperties(gt, signalGTResult);
                BeanUtils.copyProperties(gt, testResultGT);
                signalGTResultList.add(signalGTResult);
            });
            if (testResultGT.getSignalGTResultList() == null) {
                testResultGT.setSignalGTResultList(new ArrayList<>());
            }
            testResultGT.getSignalGTResultList().addAll(signalGTResultList);
        });
        return testResultGT;
    }

    /**
     * 误码率转换
     *
     * @param fdBerResultList 数据库误码率结构
     * @return 文档误码率结构
     */
    private TestResultBER getBer(List<FdTestResultsBer> fdBerResultList) {
        TestResultBER testResultBER = new TestResultBER();

        Map<Float, List<FdTestResultsBer>> berMap = fdBerResultList.stream().collect(Collectors.groupingBy(FdTestResultsBer::getBer));
        SignalBERResult signalBERResult = new SignalBERResult();
        berMap.forEach((testSubId, fdBerList) -> {
                    List<BERResult> berResultList = new ArrayList<>(fdBerList.size());
                    fdBerList.forEach(fdBer -> {
                        BERResult berResult = new BERResult();
                        BeanUtils.copyProperties(fdBer, berResult);
                        berResultList.add(berResult);
                        BeanUtils.copyProperties(fdBer, signalBERResult);
                        BeanUtils.copyProperties(fdBer, testResultBER);
                    });
                    if (signalBERResult.getBerResultList() == null) {
                        signalBERResult.setBerResultList(new ArrayList<>());
                    }
                    signalBERResult.getBerResultList().addAll(berResultList);
                }
        );
        testResultBER.setSignalBERResult(signalBERResult);
        return testResultBER;
    }

    /**
     * 链路转化
     *
     * @param linkResultList
     * @return
     */
    private List<TestResultLink> getLinkList(List<FdTestresultsLink> linkResultList) {
        return BeansUtils.copyListProperties(linkResultList, TestResultLink.class);
    }

    /**
     * 保存gt测试结果
     *
     * @param gtList
     */
    private void saveGtResult(List<TestResultGT> gtList, String diagnoseId, Integer result, String station) {
        gtList.forEach(gt -> {
            FdTestresultsGt fdGtResult = new FdTestresultsGt();
            BeanUtils.copyProperties(gt, fdGtResult);
            if (null != gt.getSignalGTResultList()) {
                gt.getSignalGTResultList().forEach(signalGTResult -> {
                    BeanUtils.copyProperties(signalGTResult, fdGtResult);
                    fdGtResult.setId(ComUtils.getUUID());
                    fdGtResult.setDiagnoseid(diagnoseId);
                    fdGtResult.setChannelid(getChannelIdByTestSubID(gt.getTestsubid()));
                    fdGtResult.setResult(result);
                    fdGtResult.setStation(station);
                    gtResultMapper.insert(fdGtResult);
                });
            }
        });
    }

    /**
     * 保存误码率测试结果
     *
     * @param berList
     */
    private void saveBerResult(List<TestResultBER> berList, String diagnoseId, Integer result, String station) {
        berList.forEach(ber -> {
            FdTestResultsBer fdBerResult = new FdTestResultsBer();
            BeanUtils.copyProperties(ber, fdBerResult);

            Example example = new Example(FdTestparamsBer.class);
            example.createCriteria()
                    .andEqualTo("diagnoseid", diagnoseId)
                    .andEqualTo("testsubid", ber.getTestsubid());
            List<FdTestparamsBer> paramsList = berParamsMapper.selectByExample(example);
            //为查询关键字赋值
            if (paramsList.size() > 0) {
                FdTestparamsBer berParam = paramsList.get(0);
                fdBerResult.setDevlink(berParam.getDevlink());
                fdBerResult.setViterbidecoderI(berParam.getViterbidecoderI());
                fdBerResult.setViterbidecoderQ(berParam.getViterbidecoderQ());
                fdBerResult.setRs223(berParam.getRs223());
                fdBerResult.setRs239(berParam.getRs223());
                fdBerResult.setLdpc(berParam.getLdpc());
            }
            setDemodulatorId(fdBerResult, diagnoseId);
            if (null != ber.getSignalBERResult()) {
                SignalBERResult signalBERResult = ber.getSignalBERResult();
                BeanUtils.copyProperties(signalBERResult, fdBerResult);
                List<BERResult> berResultList = signalBERResult.getBerResultList();
                berResultList.forEach(berResult -> {
                    BeanUtils.copyProperties(berResult, fdBerResult);
                    fdBerResult.setDiagnoseid(diagnoseId);
                    fdBerResult.setChannelid(getChannelIdByTestSubID(ber.getTestsubid()));
                    fdBerResult.setResult(result);
                    fdBerResult.setStation(station);
                    berResultMapper.insert(fdBerResult);
                });
            }
        });
    }

    /**
     * 初始化解调器ID
     */
    private void setDemodulatorId(FdTestResultsBer fdBerResult, String diagnoseId) {
        Example example = new Example(FdDiagnosetaskTest.class);
        example.createCriteria().andEqualTo("diagnoseid", diagnoseId);
        List<FdDiagnosetaskTest> testList = testMapper.selectByExample(example);
        if (testList.size() > 0) {
            try {
                String jsonParam = testList.get(0).getJsonParam();
                LoopTests loopTests = JsonUtils.jsonToBean(jsonParam, LoopTests.class, true);
                for (TestChannelBean channel : loopTests.getTestChannelBeanList()) {
                    for (DeviceParam deviceParam : channel.getDeviceParamList()) {
                        //根据设备类型判断
                        if ("MyDEMQH_KJ".equals(deviceParam.getDevType()) || "MyDEMQH".equals(deviceParam.getDevType())) {
                            fdBerResult.setDemodulatorid(deviceParam.getDevId());
                            return;
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 保存链路测试结果
     *
     * @param linkList
     */
    private void saveLinkResult(List<TestResultLink> linkList, String diagnoseId, Integer result, String station) {
        linkList.forEach(link -> {
            FdTestresultsLink fdLinkResult = new FdTestresultsLink();
            BeanUtils.copyProperties(link, fdLinkResult);

            Example example = new Example(FdTestparamsLink.class);
            example.createCriteria()
                    .andEqualTo("diagnoseid", diagnoseId)
                    .andEqualTo("testsubid", link.getTestsubid());
            List<FdTestparamsLink> paramsList = linkParamsMapper.selectByExample(example);

            //这里的闭环类型/链路需要作为查询的依据,但是测试诊断结果没有返回该字段,所以只有从参数表中查询
            if (paramsList.size() > 0) {
                fdLinkResult.setLooptype(paramsList.get(0).getLooptype());
                fdLinkResult.setDevlink(paramsList.get(0).getDevlink());
            }
            fdLinkResult.setDiagnoseid(diagnoseId);
            fdLinkResult.setChannelid(getChannelIdByTestSubID(link.getTestsubid()));
            fdLinkResult.setResult(result);
            fdLinkResult.setStation(station);
            linkResultMapper.insert(fdLinkResult);
        });
    }

    /**
     * 更新测试诊断表的状态
     *
     * @param diagnoseId
     * @param executeStatus
     */
    private void modifyTestResultByDiagnoseId(String diagnoseId, Integer executeStatus) {
        FdDiagnosetask diagnose = new FdDiagnosetask();
        FdDiagnosetaskTest testDiagnosetask = new FdDiagnosetaskTest();
        diagnose.setDiagnoseid(diagnoseId);
        testDiagnosetask.setDiagnoseid(diagnoseId);
        diagnose.setStatus(executeStatus);
        testDiagnosetask.setStatus(executeStatus);
        diagnoseTaskMapper.updateByPrimaryKeySelective(diagnose);
        testMapper.updateByPrimaryKeySelective(testDiagnosetask);
    }

    /**
     * 将结果推送到客服端
     *
     * @param result
     */
    private void promoteJob(TestResultContent result) {
        try {
            String jsonResult = JsonUtils.beanToJson(result, true);
            JobDetailImpl jd = new JobDetailImpl();
            jd.setJobClass(PromoteTestDiagnoseResultJob.class);
            jd.setKey(JobKey.jobKey(ComUtils.getUUID()));
            jd.getJobDataMap().put(PromoteTestDiagnoseResultJob.DATA_KEY, jsonResult);
            SimpleTrigger trigger = TriggerBuilder.newTrigger()
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule())
                    .startNow()
                    .build();

            jobManager.register(jd, trigger);
        } catch (JsonProcessingException e) {
            log.error("推送测试结果异常,错误信息:", e);
        }

    }


    /**
     * 获取中文的结果
     *
     * @param result
     * @return
     */
    private String getChineseResult(String result) {
        return DiagnoseConst.SUCCESS.equals(result) ? "【成功】" : "【失败】";
    }

    /**
     * 获取枚举测试结果
     *
     * @param result 字符串类型成功/失败
     * @return 枚举值
     */
    private Integer getIntegerResult(String result) {
        return DiagnoseConst.SUCCESS.equals(result) ? DiagnoseConst.DIAGNOSE_RESULT_SUCCESS : DiagnoseConst.DIAGNOSE_RESULT_FAILURE;
    }

    /**
     * 获取执行状态
     *
     * @return
     */
    private Integer getExecutorStatus(String result) {
        return DiagnoseConst.SUCCESS.equals(result) ? DiagnoseConst.DIAGNOSE_STATUS_SUCCESS : DiagnoseConst.DIAGNOSE_STATUS_FAILURE;
    }

    /**
     * 根据测试子项ID转换成通道ID
     */
    private Integer getChannelIdByTestSubID(String stringestSubID) {
        return ComUtils.strToInteger(stringestSubID);
    }

    /**
     * 根据链路和闭环类型查询信号强度
     *
     * @param devLink  链路
     * @param loopType 闭环类型
     * @return 信号强度集合
     */
    public List<Float> getLinkTestResult(String devLink, String loopType) {
        Example example = new Example(FdTestresultsLink.class);
        example.createCriteria()
                .andEqualTo("devlink", devLink)
                .andEqualTo("looptype", loopType);
        example.orderBy("testendtime").desc();
        final int pageSize = 50;
        PageHelper.startPage(1, pageSize);
        List<FdTestresultsLink> resultList = linkResultMapper.selectByExample(example);
        List<Float> signalLevelList = new ArrayList<>(resultList.size());
        resultList.forEach(result -> signalLevelList.add(result.getSignallevel()));
        return signalLevelList;
    }

    /**
     * 查询误码率的测试结果
     *
     * @param devLink         设备链路
     * @param viterbiDecoderI I路维特比编码
     * @param viterbiDecoderQ Q路维特比编码
     * @param rs223           RS223编码
     * @param rs239           RS239编码
     * @param ldpc            LDPC编码
     * @param demodulatorid   解调器 id
     * @return 测量EBN0 集合
     */
    public List<Float> getBerTestResult(String devLink,
                                        Integer viterbiDecoderI,
                                        Integer viterbiDecoderQ,
                                        Integer rs223,
                                        Integer rs239,
                                        Integer ldpc,
                                        String demodulatorid) {
        final int pageSize = 50;
        Example example = new Example(FdTestResultsBer.class);

        example.createCriteria()
                .andEqualTo("devlink", devLink)
                .andEqualTo("viterbidecoderI", viterbiDecoderI)
                .andEqualTo("viterbidecoderQ", viterbiDecoderQ)
                .andEqualTo("rs223", rs223)
                .andEqualTo("rs239", rs239)
                .andEqualTo("ldpc", ldpc)
                .andEqualTo("demodulatorid", demodulatorid);
        example.orderBy("testendtime").desc();
        PageHelper.startPage(1, pageSize);
        List<FdTestResultsBer> resultList = berResultMapper.selectByExample(example);
        List<Float> measureebn0List = new ArrayList<>(resultList.size());
        resultList.forEach(ber -> measureebn0List.add(ber.getMeasureebn0()));
        return measureebn0List;
    }

    /**
     * 查询gt值测试结果
     *
     * @param antennaId   天线id
     * @param radioSource 辐射源
     * @param frequency   测试频率
     * @return 最近50条gt值
     */
    public List<Float> getGtTestResult(String antennaId, String radioSource, Integer frequency) {
        final int pageSize = 50;
        Example example = new Example(FdTestresultsGt.class);
        example.createCriteria()
                .andEqualTo("antennaid", antennaId)
                .andEqualTo("radiosource", radioSource)
                .andEqualTo("frequency", frequency);

        example.orderBy("testendtime").desc();
        PageHelper.startPage(1, pageSize);
        List<FdTestresultsGt> resultList = gtResultMapper.selectByExample(example);
        List<Float> gtList = new ArrayList<>(resultList.size());
        resultList.forEach(gt -> gtList.add(gt.getGtvalue()));
        return gtList;
    }
}
